<?php

define('EXTRACT_STR', 1);
define('EXTRACT_INT', 2);

/**
 * Core
 * Main class, system core
 * Takes care of plugin management and action handling
 * @package
 * @author kubicek
 * @copyright Copyright (c) 2010
 * @version $Id$
 * @access public
 */
class Core
{
	public $plugins = Array();
	public $plugins_path = Array();
	public $action = '';
	public $router_id = '';
	public $used_plugin = '';

	/**
	 * Constructor
	 */
	function __construct()
	{
		global $db;

		$this->db = $db;
		$this->load_plugins();
	}

	/**
	 * Core::load_plugins()
	 * Loads plugins from plugin directory
	 *
	 * @return
	 */
	private function load_plugins()
	{
		if($handle = opendir(PLUGINS_DIR)) //lets try to open the plugin dir
		{
			while(false !== ($file = readdir($handle)))
			{
				if($file != '.' && $file != '..' && $file != '.svn') //we don`t want this
				{
					$this->plugins[] = strtolower($file);
				}
			}

			closedir($handle); //close dir handler

			//loop through plugins and read their info
			for($i = 0;$i < sizeof($this->plugins);$i++)
			{
				$path = PLUGINS_DIR.$this->plugins[$i].'/'; //path to plugin dir
				$class_filename = $path.FILE_PLUGIN_CLASS.$this->plugins[$i].'.php'; //plugin class file
				$actions_filename = $path.FILE_PLUGIN_ACTIONS.$this->plugins[$i].'.php'; //plugin actions file

				//add all paths to array, we will use em later
				$this->plugins_path[$this->plugins[$i]] = Array(
					'class' => $class_filename,
					'actions' => $actions_filename);
			}
		}
		else
		{
			$this->err('Can`t open plugins directory. Chmod maybe?');
		}
	}

	/**
	 * Core::router()
	 * Takes care of app flow. Calls right plugin with right action according to decomposed url
	 * Url should look like this: /plugin-action-id(non-mandatory)-seostuff
	 * @return
	 */
	public function router()
	{
		$url = addslashes($_GET['yaps_action']); //get url
		include CORE_DIR.FILE_PLUGIN_ACTIONS.'core.php'; //include default actions

		//we need to rename em, cause later we will fill get and post actions with plugin values
		$core_get_actions = $actions;
		unset($actions);

		//unset($_SESSION['history']);
		$_SESSION['history'][] = 'Router URL: '.$url;
		//echo '<p>Router URL: ',$url,'</p>';

		$plugin = $this->apply_routing_table($url);
		if(!$plugin)
		{
			$url = explode('-',$url); //let the url explode :)
			$plugin_name = $url[0]; //here should be plugin name
			$action_name = $url[1]; //name of action
			$this->action = $action_name;

			if($plugin_name == 'form' && $action_name == 'process')
			{
				$form = Form::load($this->post_hsc('frm_name'));
				$form->process();
			}

			if(strlen($url[2]) > 0)
			{
				$this->router_id = addslashes($url[2]);
			}

			//echo 'Plugin - ',$url[0],'<br />Action - ',$url[1],'<br />';

			if(in_array($plugin_name,$this->plugins)) //do we know this plugin?
			{
				include $this->plugins_path[$plugin_name]['actions'];
				$plugin = $this->load_plugin($plugin_name);
				$this->used_plugin = $plugin;

				if(sizeof($actions) > 0 && array_key_exists($action_name,$actions)) //does this plugin have method we want in get actions?
				{ //yeah, it does :)
					$_SESSION['plugin'] = $plugin_name; //lets note used plugin, we will use it later
					$_SESSION['action'] = $action_name; //lets note used action
					$this->save_last_page();
					$plugin->$actions[$action_name]();
					//echo 'do sessions ukladam: ',$_SESSION['plugin'],' s akci ',$_SESSION['action'],'<br />';
				}
				else
				{
					//$this->err('Hmm, action want you don`t know I, young padawan. Hmm hmmm');
					if(method_exists($plugin,'start')) //does this plugin have default start function?
					{
						$_SESSION['plugin'] = $plugin_name; //lets note used plugin, we will use it later
						$_SESSION['action'] = 'start'; //lets note used action
						$this->save_last_page();
						$plugin->start(); //call it
						//echo 'do sessions ukladam: ',$_SESSION['plugin'],' s akci ',$_SESSION['action'],'<br />';
					}
					else //no, developer is bitch! Let`s call the default one
					{
						// here should come 404 page
						$this->refresh_header('HTTP/1.0 404 Not Found');
						//$this->err('Sorry, I don`t know this function:( Calling default.');
						$default_plugin = $this->db->get_row("SELECT value FROM ".DB_PREFIX."yaps_config WHERE name = 'default_plugin'");
						unset($plugin);

						$plugin = $this->load_plugin($default_plugin['value']);
						$_SESSION['plugin'] = $default_plugin['value']; //lets note used plugin, we will use it later
						$_SESSION['action'] = 'start'; //lets note used action
						$this->save_last_page();
						//echo 'do sessions ukladam: ',$_SESSION['plugin'],' s akci ',$_SESSION['action'],'<br />';
						$plugin->start();
					}
				}
			}
			elseif(sizeof($core_get_actions) > 0 && array_key_exists($action_name,$core_get_actions)) //do we have this get method in core?
			{
				$this->$core_get_actions[$action_name]();
			}
			else
			{
				//here should go 404 page
				//$this->err('Sorry, I don`t know this function:( Calling default.');
				$default_plugin = $this->db->get_row("SELECT value FROM ".DB_PREFIX."yaps_config WHERE name = 'default_plugin'");
				if(!$default_plugin) $this->err('Fatal error: Can`t load default plugin',1);

				$plugin = $this->load_plugin($default_plugin['value']);
				$this->used_plugin = $plugin;
				$_SESSION['plugin'] = $default_plugin['value']; //lets note used plugin, we will use it later
				$_SESSION['action'] = 'start'; //lets note used action
				$this->save_last_page();
				//echo 'do sessions ukladam: ',$_SESSION['plugin'],' s akci ',$_SESSION['action'],'<br />';
				$plugin->start();
			}
		}

		$this->generate_sidebar_etc($plugin);
	}

	/**
	 * Core::apply_routing_table()
	 * Try to apply routing table rules.
	 * @param mixed $url
	 * @return False, if no rule is matched or instance of plugin
	 */
	private function apply_routing_table($url)
	{
		$query = $this->db->query("SELECT * FROM ".DB_PREFIX."yaps_routing_table WHERE url LIKE ;",$url);
		if($this->db->num_rows() > 0)
		{
			$row = $this->db->get_row();

			if($this->is_plugin($row['plugin']))
			{
				$plugin = $this->load_plugin($row['plugin']);
				include $this->plugins_path[$row['plugin']]['actions'];

				if(sizeof($actions) > 0 && array_key_exists($row['action'],$actions))
				{
					if(strlen($row['id_for_action']) > 0) $this->router_id = $row['id_for_action'];

					$_SESSION['plugin'] = $row['plugin']; //lets note used plugin, we will use it later
					$_SESSION['action'] = $row['action']; //lets note used action
					$this->save_last_page();
					$plugin->$actions[$row['action']]();
					return $plugin;
				}
				elseif($row['action'] == 'start' && method_exists($plugin,'start'))
				{
					$_SESSION['plugin'] = $row['plugin']; //lets note used plugin, we will use it later
					$_SESSION['action'] = 'start'; //lets note used action
					$this->save_last_page();
					$plugin->start();
					return $plugin;
				}
				else return false;
			}
			else return false;
		}
		else return false;
	}

	/**
	 * Core::add_to_routing_table()
	 * Add or update rule in routing table
	 * @param mixed $url
	 * @param mixed $plugin
	 * @param mixed $action
	 * @param mixed $id
	 * @return
	 */
	public function add_to_routing_table($url,$plugin,$action,$id)
	{
		$query = $this->db->query("SELECT * FROM ".DB_PREFIX."yaps_routing_table WHERE plugin = '".$plugin."' AND action = '".$action."' AND id_for_action = '".$id."'");
		if($this->db->num_rows() > 0)
		{
			$row = $this->db->get_row();
			$this->db->query("UPDATE ".DB_PREFIX."yaps_routing_table SET url = '".$url."' WHERE id = ".$row['id']);
		}
		else
		{
			$this->db->query("INSERT INTO ".DB_PREFIX."yaps_routing_table VALUES('0','".$url."','".$plugin."','".$action."','".$id."')");
		}
	}

	/**
	 * Core::generate_sidebar_etc()
	 * Generates sidebar and footer from selected plugin
	 * @param mixed $plugin
	 * @return
	 */
	private function generate_sidebar_etc($plugin)
	{
		if($plugin->has_sidebar)
		{
			$plugin->generate_sidebar();
		}

		if($plugin->has_footer)
		{
			$plugin->generate_footer();
		}
	}

	/**
	 * Core::plugin_info()
	 * Prints info about all loaded plugins
	 * @return
	 */
	public function plugin_info()
	{
		for($i = 0; $i < sizeof($this->plugins); $i++)
		{
			$plugin = $this->load_plugin($this->plugins[$i]);
			$plugin->say_hello();
			unset($plugin);
		}
	}

	/**
	 * Core::err()
	 * Add new error to error list
	 * @param mixed $text
	 * @return
	 */
	public function err($text, $fatal = 0)
	{
		$_SESSION['err'][] = $text;

		if($fatal) die($text);
	}

	/**
	 * Core::msg()
	 * Add new msg to msg list
	 * @param mixed $text
	 * @return
	 */
	public function msg($text)
	{
		$_SESSION['msg'][] = $text;
	}

	/**
	 * Core::print_alert()
	 * Print everything that is in err and msg arrays in session
	 * @return
	 */
	public function print_alert()
	{
		ob_start();
		for($i = 0; $i < sizeof($_SESSION['err']); $i++)
		{
			if(strlen($_SESSION['err'][$i]) > 0)
				echo '<div class="error">Yaps error: '.$_SESSION['err'][$i].'</div>';
		}
		$_SESSION['err'] = '';

		for($i = 0; $i < sizeof($_SESSION['msg']); $i++)
		{
			if(strlen($_SESSION['msg'][$i]) > 0)
				echo '<div class="msg">Yaps message: '.$_SESSION['msg'][$i].'</div>';
		}
		$_SESSION['msg'] = '';

		return ob_get_clean();
	}

	/**
	 * Core::get()
	 * Gets value from GET safe way
	 * @param mixed $index
	 * @return mixed Slashed GET value
	 */
	public function get($index)
	{
		if(!is_array($_POST[$index]) && strlen($_GET[$index]) < 1) return false;
		return addslashes($_GET[$index]);
	}

	/**
	 * Core::post()
	 * Gets value from POST safe way
	 * @param mixed $index
	 * @return mixed Slashed POST value
	 */
	public function post($index)
	{
		if(!is_array($_POST[$index]) && strlen($_POST[$index]) < 1) return false;
		return (is_array($_POST[$index])) ? $_POST[$index] : addslashes($_POST[$index]);
	}

	/**
	 * Core::get_hsc()
	 * Gets value from GET safe way with HSC
	 * @param mixed $index
	 * @return mixed Slashed GET value
	 */
	public function get_hsc($index)
	{
		if(!is_array($_POST[$index]) && strlen($_GET[$index]) < 1) return false;
		return $this->hsc($_GET[$index]);
	}

	/**
	 * Core::post_hsc()
	 * Gets value from POST safe way with HSC
	 * @param mixed $index
	 * @return mixed Slashed POST value
	 */
	public function post_hsc($index)
	{
		if(!is_array($_POST[$index]) && strlen($_POST[$index]) < 1) return false;
		return $this->hsc($_POST[$index]);
	}

	/**
	 * Core::hsc()
	 * Shortcut to htmlspecialchars
	 * @param mixed $string
	 * @return mixed htmlspecialchared $string
	 */
	public function hsc($string)
	{
		return htmlspecialchars($string,ENT_QUOTES);
	}

	/**
	 * Core::refresh_header()
	 * Refresh page with PHP header function
	 * @param mixed $where
	 * @return
	 */
	public function refresh_header($where,$inweb = 1)
	{
		global $theme;

		$theme->render = false; //we shall not render!
		if($inweb) $where = WEB_URL.$where;
		header('Location: '.$where);
	}

	/**
	 * Core::refresh()
	 * Redirect page with standart meta tag. Works everywhere :)
	 * @param mixed $where
	 * @param mixed $time
	 * @return
	 */
	public function refresh($where,$time = 0)
	{
		global $theme;
		if(isset($theme))
		{
			$theme->add_to_head('<meta http-equiv="refresh" content="'.$time.';'.$where.'" />');
		}
		else
		{
			echo '<meta http-equiv="refresh" content="',$time,';',$where,'" />';
		}
	}

	/**
	 * Core::refresh_js()
	 * Redirec page with jquery trick
	 * @param mixed $where
	 * @return
	 */
	public function refresh_js($where)
	{
		global $theme;

		$theme->include_jquery();

		$theme->js('$(location).attr(\'href\',\''.$where.'\');');
	}

	/**
	 * Core::load_plugin()
	 * Load plugin and return reference
	 * @param mixed $plugin
	 * @return reference $new_plugin
	 */
	public function load_plugin($plugin)
	{
		if (!class_exists($plugin))
		{
			if(file_exists($this->plugins_path[$plugin]['class']))
			{
				include $this->plugins_path[$plugin]['class'];
			}
			else
			{
				$this->err('<b>Fatal Yaps! error:</b> Can`t load plugin: '.$plugin.'!',1);
			}
		}

		$new_plugin = new $plugin;

		//is this plugin installed and does it need install?
		if($this->is_installed($plugin) < 1 && $new_plugin->needs_install == true)
		{
			$res = $new_plugin->install();
			if(!$res) $this->err("Error! Can`t install plugin <b>".$plugin."</b>. Please check your DB",1);
		}

		return $new_plugin;
	}

	/**
	 * Core::is_installed()
	 * Simple function to determine if $plugin is installed in DB
	 * @param mixed $plugin
	 * @return
	 */
	public function is_installed($plugin)
	{
		$count = $this->db->num_rows("SELECT * FROM ".DB_PREFIX."yaps_config WHERE name = 'plugin_".$plugin."_installed'");
		return ($count > 0) ? true : false;
	}

	/**
	 * Core::is_plugin()
	 * Simple function to determine if there is a plugin with name $plugin
	 * @param mixed $plugin
	 * @return
	 */
	public function is_plugin($plugin)
	{
		if(file_exists($this->plugins_path[$plugin]['class']))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * Core::encode_url()
	 * Encode URL to right format for using in links
	 * @param mixed $text
	 * @return
	 */
	public function encode_url($text)
	{
		$text = $this->remove_diacritics($text);

		$text = strtolower(trim($text));
		// replace all white space sections with a dash
		$text = str_replace(' ', '-', $text);
		// strip all non alphanum or -
		$text = ereg_replace("[^A-Za-z0-9\-]", "", $text);

		return $text;
	}

	/**
	 * Core::remove_diacritics()
	 * Old function i wrote years ago, handle Czech diacritics
	 * @param mixed $text
	 * @return
	 */
	public function remove_diacritics($text)
	{
		$text = trim($text);
		$text = str_replace('\'','!@#$%Pirozek',$text); //nahrazeni '

		setlocale(LC_CTYPE, 'cs_CZ.utf-8');

		$text = str_replace('\'','',iconv("utf-8", "us-ascii//TRANSLIT", $text));

		$text = str_replace('!@#$%Pirozek','\'',$text); //a jeho nahrazeni zpatky, kvuli iconv

		return $text;
	}

	/**
	 * Core::print_ar()
	 * Nicer print of array
	 * @param mixed $array
	 * @param integer $count
	 * @return
	 */
	public function print_ar($array, $count = 0)
	{
		//echo 'volam se';
		$i = 0;
		$tab = '';
		while($i != $count)
		{
			$i++;
			$tab .= "&nbsp;&nbsp;|&nbsp;&nbsp;";
		}
		foreach($array as $key => $value)
		{
			if(is_array($value))
			{
				echo $tab . "[<strong><u>$key</u></strong>]<br />";
				$count++;
				$this->print_ar($value, $count);
				$count--;
			}
			else
			{
				$tab2 = substr($tab, 0, - 12);

				if(!is_numeric($key) || strlen($value) > 0)
				{
					echo "$tab2~ $key: <strong>$value</strong><br />";
				}
			}
			$k++;
		}
		$count--;
	}

	/**
	 * Core::convert_datetime()
	 * Converts MySQL DATETIME to something better :) -> DD.MM.YYYY HH:MM <-
	 * @param mixed $datetime
	 * @return
	 */
	public function convert_datetime($datetime)
	{
		//2010-07-06 02:00:00
		$half = explode(' ',$datetime); //now we have date and time separated
		$date = $half[0];
		$time = $half[1];

		$date = explode('-',$date); //explode it
		$time = explode(':',$time);

		//and create our format
		$out = sprintf('%02d:%02d %02d.%02d.%04d',$time[0],$time[1],$date[2],$date[1],$date[0]);
		return $out;
	}

	/**
	 * Core::get_ip()
	 * Return IP address of user
	 * @return
	 */
	public function get_ip()
	{
		return $_SERVER['REMOTE_ADDR'];
	}

	/**
	 * Core::md5()
	 * Yaps md5 function that adds salt to md5 hash
	 * @param mixed $string
	 * @return
	 */
	public function md5($string)
	{
		return md5($string.SALT);
	}

	/**
	 * Core::where_am_i()
	 * Return url where is user now :)
	 * @param mixed $full_url
	 * @return
	 */
	public function where_am_i($full_url = true, $refer = false)
	{
		if($refer == true) return substr(WEB_URL,0,-1).$_SERVER['REQUEST_URI'];

		$url_string = $_SESSION['plugin'].'-'.$_SESSION['action'].(($this->router_id) ? '-'.$this->router_id : '');

		if($full_url) return WEB_URL.$url_string;
		else return $url_string;
	}

	/**
	 * Core::current_plugin()
	 * Return current plugin
	 * @return
	 */
	public function current_plugin()
	{
		return $_SESSION['plugin'];
	}

	/**
	 * Core::current_action()
	 * Return current action
	 * @return
	 */
	public function current_action()
	{
		return $_SESSION['action'];
	}

	public function save_last_page()
	{

	}

	/**
	 * Core::load_last_page()
	 * Load referer from session
	 * @return
	 */
	public function load_last_page()
	{
		$where = substr($_SERVER['HTTP_REFERER'],strlen(WEB_URL),strlen($_SERVER['HTTP_REFERER']) - strlen(WEB_URL));
		return $where;
	}

	/**
	 * Core::array_extract()
	 * Return array only with int keys or string keys
	 * Taken from - http://php.net/manual/en/function.array-keys.php
	 * @param mixed $array
	 * @param integer $extract_type 1 - return int keys, 2 - return string keys
	 * @return
	 */
	public function array_extract($array, $extract_type = 1)
	{
		foreach ( $array as $key => $value )
		{
			if ( $extract_type == 1 && is_string($key) )
			{
				// delete string keys
				unset($array[$key]);
			}
			elseif ( $extract_type == 2 && is_int($key) )
			{
				// delete integer keys
				unset($array[$key]);
			}
		}

		return $array;
	}

	public function send_mail($komu, $text, $subject, $echo = 0)
	{
		$head .= "From: Jakub \"Pirozek\" Ludwig<xludwi01@stud.fit.vutbr.cz>\n";
		$head .= "Reply-To: xludwi01@stud.fit.vutbr.cz\n";
		$head .= "X-Mailer: PHP\n";

		$subject = html_entity_decode($subject);

		$predmet = "=?utf-8?B?" . base64_encode($this->autoUTF($subject)) . "?=";
		$head .= "MIME-Version: 1.0\n";
		$head .= "Content-Type: text/html; charset=\"utf-8\"\n";
		$head .= "Content-Transfer-Encoding: quoted-printable\n";
		$head .= "Return-Path: xludwi01@stud.fit.vutbr.cz\n";
		// $text = str_replace('=','=3D', $text);
		if(function_exists('imap_8bit'))
		{
			$zprava = imap_8bit($this->autoUTF($text));
		}
		else
		{
			$zprava = $this->autoUTF($text);
		}
		$mail = mail($komu, $predmet, $zprava, $head);

		if($echo)
		{
			if($mail):
				$this->msg("Mail has been sent!");
			else:
				$this->err("Oops, can`t send mail. Check your SMTP settings.");
			endif;
		}
	}

	// zdroj - http://diskuse.jakpsatweb.cz/?action=vthread&forum=9&topic=2111#3
	/**
	 * ===============================================
	 * 		DETEKCE POUZIVANEHO KODOVANI + PREKODOVANI
	 * ===============================================
	 */
	public function autoUTF($s)
	{
		// detect UTF-8
		if (preg_match('#[\x80-\x{1FF}\x{2000}-\x{3FFF}]#u', $s))
			return $s;
		// detect WINDOWS-1250
		if (preg_match('#[\x7F-\x9F\xBC]#', $s))
			return iconv('WINDOWS-1250', 'UTF-8', $s);
		// assume ISO-8859-2
		return iconv('ISO-8859-2', 'UTF-8', $s);
	}
}

?>